package com.ruoyi.common.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.reflectasm.MethodAccess;
import lombok.val;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基础 service
 */
public abstract class BaseServiceImpl<T> {

  @Resource
  public BaseMapper<T> baseMapper;

  @Resource
  protected ObjectMapper om;

  public int insert(T entity) {
    return baseMapper.insert(entity);
  }

  public int deleteById(Serializable id) {
    return baseMapper.deleteById(id);
  }

  public int deleteById(T entity) {
    return baseMapper.deleteById(entity);

  }

  public int deleteByEntity(T entity) {
    return baseMapper.deleteByMap(convertMap(entity));
  }

  public int delete(Wrapper<T> queryWrapper) {
    return baseMapper.delete(queryWrapper);
  }

  public int deleteBatchIds(Collection<? extends Serializable> idList) {
    return baseMapper.deleteBatchIds(idList);
  }

  public int updateById(T entity) {
    return baseMapper.updateById(entity);
  }

  public int update(T entity, Wrapper<T> updateWrapper) {
    return baseMapper.update(entity, updateWrapper);
  }

  public T selectById(Serializable id) {
    return baseMapper.selectById(id);
  }

  public List<T> selectBatchIds(Collection<? extends Serializable> idList) {
    return baseMapper.selectBatchIds(idList);
  }

  public List<T> selectByEntity(T entity) {
    return baseMapper.selectByMap(convertMap(entity));
  }

  public T selectOne(Wrapper<T> queryWrapper) {
    List<T> ts = baseMapper.selectList(queryWrapper);
    if (CollectionUtils.isNotEmpty(ts)) {
      if (ts.size() != 1) {
        throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records", new Object[0]);
      } else {
        return ts.get(0);
      }
    } else {
      return null;
    }
  }

  public Long selectCount(Wrapper<T> queryWrapper) {
    return baseMapper.selectCount(queryWrapper);
  }

  public List<T> selectList(Wrapper<T> queryWrapper) {
    return baseMapper.selectList(queryWrapper);
  }

  public List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper) {
    return baseMapper.selectMaps(queryWrapper);
  }

  public List<Object> selectObjs(Wrapper<T> queryWrapper) {
    return baseMapper.selectObjs(queryWrapper);
  }

  public <P extends IPage<T>> P selectPage(P page, Wrapper<T> queryWrapper) {
    return baseMapper.selectPage(page, queryWrapper);
  }

  public <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, Wrapper<T> queryWrapper) {
    return baseMapper.selectMapsPage(page, queryWrapper);
  }

  private Map<String, Object> convertMap(T entity) {
    val map = new HashMap<String, Object>();
    MethodAccess ma = MethodAccess.get(entity.getClass());
    Arrays.stream(ma.getMethodNames())
        .filter(s -> s.startsWith("get"))
        .forEach(s -> {
          val m = ma.invoke(entity, s);
          if (m != null && !"".equals(m) && !(m instanceof Map)) {
            map.put(MethodToField(s), m);
          }
        });
    return map;
  }


  private String MethodToField(String name) {
    name = name.replaceFirst("get", "");
    String f1 = name.substring(0, 1);
    String f2 = f1.toLowerCase();
    return name.replaceFirst(f1, f2);
  }

}
